package com.stars.util.ecrypt;

import com.alibaba.fastjson2.JSONObject;
import com.stars.util.cache.CacheUtil;
import com.stars.util.context.SpringContextUtil;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author : Rocks
 * @version : 1.0
 * @date : 2022/10/17 18:22
 * @description : RSA加解密
 */
public class RSAUtil {

    private static final CacheUtil cacheUtil;

    static{
        cacheUtil = SpringContextUtil.getBean(CacheUtil.class);
    }

    /**
     * 初始化RSA加密公钥和私钥
     * @author : Rocks
     * @date :  2023/2/26 20:46
     * @return JSONObject
     */
    public static JSONObject initRsaKey()  {
        try{
            JSONObject obj = new JSONObject();
            RSAUtil.RSAKeyPair keyPair = RSAUtil.generateKeyPair();
            String rsaPublic = keyPair.getPublicKey();
            String rsaPrivate = keyPair.getPrivateKey() ;
            obj.put("publicKey",rsaPublic);
            obj.put("privateKey",rsaPrivate);
            return obj;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取指定redis中的公钥
     * @author : Rocks
     * @date :  2023/2/26 20:46
     * @param redisKey redis键
     * @return String
     */
    public static String getPublicKey(String redisKey){
        JSONObject rsa = getRSA(redisKey);
        return rsa.getString("publicKey");
    }

    /**
     * 获取指定redis中的私钥
     * @author : Rocks
     * @date :  2023/2/26 20:47
     * @param redisKey redis键
     * @return String
     */
    public static String getPrivateKey(String redisKey){
        JSONObject rsa = getRSA(redisKey);
        return rsa.getString("privateKey");
    }

    /**
     * 获取redis中的密钥
     * @author : Rocks
     * @date :  2023/2/26 20:47
     * @param redisKey redis键
     * @return JSONObject
     */
    private static JSONObject getRSA(String redisKey){
        JSONObject obj = cacheUtil.getValue(false,redisKey, JSONObject.class);
        if(obj==null){
            JSONObject rsaObj = initRsaKey();
            assert rsaObj != null;
            cacheUtil.setValue(false, redisKey, rsaObj);
            return rsaObj;
        }
        return obj;
    }

    /**
     * 使用私钥进行解密
     * @author : Rocks
     * @date :  2023/2/26 20:48
     * @param privateKeyText 私钥
     * @param text 密文
     * @return String 明文
     */
    public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] result = cipher.doFinal(Base64.decodeBase64(text));
        return new String(result);
    }

    /**
     * 使用公钥进行加密
     * @author : Rocks
     * @date :  2023/2/26 20:49
     * @param publicKeyText 公钥
     * @param text 明文
     * @return String 密文
     */
    public static String encryptByPublicKey(String publicKeyText, String text) throws Exception {
        X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] result = cipher.doFinal(text.getBytes());
        return Base64.encodeBase64String(result);
    }

    /**
     * 构建RSA密钥对
     * @author : Rocks
     * @date :  2023/2/26 20:50
     * @return RSAKeyPair
     */
    public static RSAKeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);

        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
        String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
        String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
        return new RSAKeyPair(publicKeyString, privateKeyString);
    }


    /**
     * RSA密钥对对象
     */
    public static class RSAKeyPair {

        private final String publicKey;
        private final String privateKey;

        public RSAKeyPair(String publicKey, String privateKey) {
            this.publicKey = publicKey;
            this.privateKey = privateKey;
        }

        public String getPublicKey() {
            return publicKey;
        }

        public String getPrivateKey() {
            return privateKey;
        }
    }
}
